package thread;

import java.util.PriorityQueue;

//创建一个类，用来描述定时器的一个任务
class MyTimerTask implements Comparable<MyTimerTask>{
    private long time;
    private Runnable runnable;
    public MyTimerTask(Runnable runnable,long delay){
        //delay是一个相对的时间差，形如3000这样的数值
        //构造time要根据当前系统时间和delay进行构造
        time=System.currentTimeMillis()+delay;
        this.runnable=runnable;
    }
    public long getTime(){
        return time;
    }
    public Runnable getRunnable(){
        return runnable;
    }
    @Override
    public int compareTo(MyTimerTask o){
        //认为时间小的，优先级高，最终时间最小的元素，就会放到队首
        //正排二参前，负排一参前
        return (int)(this.time-o.time);
    }
}
class MyTimer{
    //使用优先级队列，来保存上述的N歌任务
    private PriorityQueue<MyTimerTask>queue=new PriorityQueue<>();
    //用来加锁的对象
    private Object locker=new Object();
    //定时器的核心方法，就是把要执行的任务添加到队列中
    public void schedule(Runnable runnable,long delay){
        synchronized (locker){
            MyTimerTask task=new MyTimerTask(runnable,delay);
            queue.offer(task);
            //每次来新的任务，都唤醒一下之前的扫描线程，好让扫描线程根据最新的任务情况，重新规划
            //等待的时间
            locker.notify();
        }
    }

    //MyTimer中还需要构造一个“扫描线程”，一方面去负责监控队首元素是否到点了，是否应该执行；一方面
    //当任务到点之后，就要调用这里的Runnable的Run方法去完成任务
    public MyTimer(){
        //扫描线程
        Thread t = new Thread(()->{
            while (true) {
                try{
                 synchronized (locker) {
                     while (queue.isEmpty()) {
                         //队列为空，不该取元素
                         //此处使用wait等待更合适，如果使用continue，就会是这个线程
                         //while循环运行的飞快，也会陷入一个高频占用cpu的状态（忙等）
                         locker.wait();
                     }
                     MyTimerTask task = queue.peek();
                     long curTime=System.currentTimeMillis();
                     if(curTime>=task.getTime()){
                             queue.poll();
                             task.getRunnable().run();
                         }
                     else {
                             //让当前扫描线程休眠一下，按照时间差来进行休眠
                           locker.wait(task.getTime()-curTime);
                         }
                     }
             }
         catch (InterruptedException e){
             e.printStackTrace();
         }
            }
        });
        t.start();
    }
}
//写一个定时器
public class demo4
{
    public static void main(String[] args) {
        MyTimer timer = new MyTimer();
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello 3");
            }
        },3000);
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello 2");
            }
        },2000);
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello 1");
            }
        },1000);
        System.out.println("程序开始运行");
    }
}
